home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 April: Mac OS SDK / Dev.CD Apr 96 SDK / Dev.CD Apr 96 SDK1.toast / Development Kits (Disc 1) / OpenDoc / Documentation / Tech Notes & Articles / Recipes / Part Persistency / Lazy Frame Internalization < prev    next >
Encoding:
Text File  |  1995-04-20  |  5.2 KB  |  87 lines  |  [TEXT/ttxt]

  1. OpenDoc™ Recipes
  2.  
  3. Lazy Frame Internalization
  4. by The OpenDoc Design Team
  5. April 20, 1995
  6.  
  7.  
  8. © 1993-1995  Apple Computer, Inc. All Rights Reserved.
  9. Apple, the Apple logo, and Macintosh are registered trademarks of Apple Computer, Inc.
  10. Mac and OpenDoc are trademarks of Apple Computer, Inc.
  11.  
  12.  
  13. Winning Through Laziness
  14.  
  15. There are situations in OpenDoc where eagerly doing work as soon as possible is not the best thing to do, and the work should be deferred until it really needs to be done. Internalization is usually a good candidate for being lazy. In general, don't internalize data until it is needed, or you can predict it will be needed soon (e.g. you might pre-fetch the next page so scrolling will be fast). A particular case of lazy internalization involves your part's frames, both display frames and embedded frames.
  16.  
  17. Since OpenDoc places very few requirements on a part's internal representation, your part is free to organize its data however it pleases. The only requirements relevant to frames are that your part must be able to supply an EmbeddedFramesIterator for its embedded frames, and it should externalize a list of its display frames in a standard property of its storage unit.
  18.  
  19. For very simple containing parts, there won't be much advantage in lazily interalizing embedded frames. But for large containing parts, the advantages can be quite significant. For example, a containing part which embeds five thousand frames (think CD-ROM here) would not want to internalize all of those frames at the same time. There would be no way to display all the frames simultaneously, and a large amount of memory would effectively be wasted on keeping those persistent objects resident. All parts should consider lazy internalization of display frames, since your part has no control over the number of display frames that may be added to it.
  20.  
  21.  
  22. How to be Lazy
  23.  
  24. The main trick to lazy frame internalization is stopping before you go too far. In InitPartFromStorage, you should stop short of calling draft->GetFrame(). Instead, just hang on to the frame ID that you got from the storageUnitRef. (Remember that display frame references should be weak, so they may not actually have a frame or ID at the other end.) The minimal way to deal with this ID is to create a structure that can hold a frame pointer and a frame ID. Anywhere in your code you would have stored a frame reference, store one of these structures instead. If the structure doesn't have a frame yet, use the ID to get it, then store it in the structure for next time (remember to increment the frame's refcount).
  25.  
  26. For slightly more effort up-front, you can have a much easier time of it later. You can create a class that stores a frame reference and a frame ID, and does the GetFrame for you when necessary. The class "Futon" below is an example of such. (Please don't try to read any significance into the name. It's just a random word that was easy to type.)
  27.  
  28. Getting Laziness to Work for You
  29.  
  30. Now that your part is more relaxed about internalizing its frames, here's how it can take advantage of being lazy.
  31.  
  32. • Don't get a frame unless you really need to. You've already fixed your part so that instead of direct frame references in its content, it has futons instead. Now it would be a real waste if you went and made all those futons get their frames right away. As a containing part, your part probably has a pretty good idea of where its embedded frames are located, and how big they are - you need this information to determine when to add a facet to a frame to make it visible. So be lazy and don't get the embedded frame from the futon until you need to add a facet to it, or perform some other operation on it. Just don't get it for the sake of getting it.
  33.  
  34. • Purge frames when memory is low. When your part gets a Purge() call, it should attempt to free up memory. If you are set up for lazy internalization, it's easy to purge frames. This only works if you don't keep direct frame references anywhere. First off, only purge frames that are not currently visible. Start by removing a frame's facets. Then call Release() on the frame, and null it out in the Futon. If a frame's embedded and containing parts both do this, the reference count of the frame should drop to zero, and the object can be flushed from memory. Don't call Close() on an embedded frame to purge it from memory - it's an awful lot of work to Close and re-Connect frames, and the technique described above works just as well if not better.
  35.  
  36. Sample Code
  37.  
  38. #include "ODTypes.h"
  39. #include "ODUtils.h"
  40. #include "Draft.xh"
  41. #include "Frame.xh"
  42.  
  43. class Futon
  44. {
  45. public:
  46.  
  47.     Futon(ODDraft* draft, ODID frameID);
  48.     ~Futon();
  49.  
  50.     ODFrame*    GetFrame(Environment* ev);
  51.     void        Purge(Environment* ev);
  52.  
  53.     ODDraft*    fDraft;
  54.     ODID        fFrameID;
  55.     ODFrame*    fFrame;
  56. };
  57.  
  58. Futon::Futon(ODDraft* draft, ODID frameID)
  59. {
  60.     // note: I'm being skanky and not refcounting the draft, because
  61.     // the draft is referenced from the part's storage unit, so it's
  62.     // not going away while the futon (and thus the part) is still around.
  63.     
  64.     fDraft = draft;
  65.     fFrameID = frameID;
  66.     fFrame = kODNULL;
  67. }
  68.  
  69. Futon::~Futon()
  70. {
  71.     ODSafeReleaseObject(fFrame);
  72. }
  73.  
  74. ODFrame*
  75. Futon::GetFrame(Environment* ev)
  76. {
  77.     if ( fFrame == kODNULL )
  78.         fFrame = fDraft->GetFrame(ev, fFrameID);
  79.     return fFrame;
  80. }
  81.  
  82. void
  83. Futon::Purge(Environment* ev)
  84. {
  85.     ODReleaseObject(ev, fFrame);
  86. }
  87.